package com.ybear.ybcomponent.widget.dialog

import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.res.Resources
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.provider.Settings
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams
import android.view.Window
import android.view.WindowManager
import android.widget.LinearLayout
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.annotation.LayoutRes
import androidx.annotation.RequiresPermission
import androidx.annotation.StringRes
import androidx.annotation.StyleRes
import com.ybear.ybcomponent.R
import com.ybear.ybcomponent.Utils
import com.ybear.ybcomponent.widget.dialog.DialogInit.Companion.get
import com.ybear.ybcomponent.widget.shape.ShapeLinearLayout

open class DialogConfig(private val mContext: Context, dialogX: DialogX?, @StyleRes themeResId: Int) {
    @Retention(AnnotationRetention.SOURCE)
    private annotation class Tag {
        companion object {
            const val TITLE = "TITLE"
            const val BUTTON = "BUTTON"
        }
    }

    internal val mDialog: DialogX = dialogX ?: DialogX(mContext, themeResId)
    private val mLayout: ShapeLinearLayout = ShapeLinearLayout(mContext)
    private val mInit: DialogInit = get()
    private val mStyle: WindowStyle = WindowStyle( mContext, mLayout )
    private var mDialogOption: DialogOption? = null
    private var mDialogButton: DialogButton? = null
    private var enableMeasure = false

    var dialogLifecycle: DialogLifecycle? = null
        private set
    open val attributes = LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT )
    open var childView: View? = null
    open val defTitleTextStyle: TextStyle
        /**
         * 获取默认标题文本样式
         * @return  文本样式
         */
        get() = TextStyle()
            .setTextColor( mInit.defTitleColor )
            .setTextColorInt( mInit.defTitleColorInt )
            .setTextSize( mInit.defTitleTextSize.toFloat() )
            .setPadding(
                dp2Px( mInit.defTitleLeftPadding ),
                dp2Px( mInit.defTitleTopPadding ),
                dp2Px( mInit.defTitleRightPadding ),
                dp2Px( mInit.defTitleBottomPadding )
            )
    open val defMessageTextStyle: TextStyle
        /**
         * 获取默认内容文本样式
         * @return  文本样式
         */
        get() {
            val pTop: Int = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                16
            } else {
                mInit.defMessageBottomPadding
            }
            return TextStyle()
                .setTextColorInt( Color.BLACK )
                .setGravity( Gravity.START or Gravity.TOP )
                .setMaxLines( 8 )
                .setEnableHorizontalScroll( true )
                .setPadding(
                    dp2Px( mInit.defMessageLeftPadding ),
                    dp2Px( pTop ),
                    dp2Px( mInit.defMessageRightPadding ),
                    dp2Px( mInit.defMessageBottomPadding )
                )
        }
    open val window: Window?
        /**
         * 获取Dialog的Window
         * @return  [android.view.Window]
         */
        get() = mDialog.window
    open val root: LinearLayout
        get() = mLayout

    open val parentLayoutParam: LinearLayout.LayoutParams
        get() {
            val lp = LinearLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT
            )
            lp.gravity = Gravity.START
            return lp
        }

    open val defaultLayoutParams: LinearLayout.LayoutParams
        /**
         * 获取默认布局参数
         * @return  参数
         */
        get() {
            val lp = LinearLayout.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT
            )
            lp.gravity = Gravity.START
            return lp
        }
    open val dialogLayoutParams: LinearLayout.LayoutParams
        get() {
            val lp = LinearLayout.LayoutParams(
                (resources.displayMetrics.widthPixels / 1.4F).toInt(),
                LayoutParams.WRAP_CONTENT
            )
            lp.topMargin = dp2Px( 12 )
            return lp
        }
    open val matchLayoutParams: LayoutParams
        get() = LayoutParams(
            LayoutParams.MATCH_PARENT,
            LayoutParams.MATCH_PARENT
        )

    internal constructor(context: Context, @StyleRes themeResId: Int) : this(context, null, themeResId)

    fun initView() : DialogConfig {
        val lp = LinearLayout.LayoutParams(
            LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT
        ).apply {
            gravity = Gravity.START or Gravity.TOP
            mLayout.layoutParams = this
        }
        mLayout.orientation = LinearLayout.VERTICAL
        mLayout.gravity = lp.gravity
        theme( R.style.defaultDialog )
        transparentBackgroundByRoot()
        return this
    }

    open val resources: Resources
        get() = mContext.resources

    /**
     * 设置背景资源
     * @param drawable  资源
     * @return          this
     */
    open fun backgroundDrawable(drawable: Drawable?): DialogConfig {
        mStyle.backgroundDrawable = drawable
        return this
    }

    /**
     * 设置背景资源id
     * @param res       资源id
     * @return          this
     */
    open fun backgroundDrawableResource(@DrawableRes res: Int): DialogConfig {
        mStyle.setBackgroundDrawableResource(res)
        return this
    }

    open fun backgroundColor(@ColorRes color: Int): DialogConfig {
        mStyle.setBackgroundColor( color )
        return this
    }

    open fun backgroundColorInt(@ColorInt color: Int): DialogConfig {
        mStyle.setBackgroundColorInt( color )
        return this
    }

    /**
     * 设置圆角
     * @param radius    圆滑度
     * @return          this
     */
    open fun cornerRadius(radius: Int): DialogConfig {
        cornerRadius.setCornerRadius(radius.toFloat())
        return this
    }

    open fun cornerRadiusTop(radius: Int): DialogConfig {
        cornerRadius.setCornerRadiusTop(radius.toFloat())
        return this
    }

    open fun cornerRadiusBottom(radius: Int): DialogConfig {
        cornerRadius.setCornerRadiusBottom(radius.toFloat())
        return this
    }

    open val cornerRadius: CornerRadius
        get() = mStyle.cornerRadius

    /**
     * 设置透明背景
     * @return          this
     */
    open fun transparentBackground(): DialogConfig {
        return backgroundColor(R.color.translucence)
    }

    /**
     * 设置透明背景 Parent 布局
     * @return          this
     */
    open fun transparentBackgroundByRoot(): DialogConfig {
        return backgroundColorIntByRoot( Color.TRANSPARENT )
    }

    /**
     * 设置颜色背景 Parent 布局
     * @return          this
     */
    open fun backgroundColorByRoot(@ColorRes color: Int): DialogConfig {
        mStyle.setBackgroundColorByRoot( color )
        return this
    }

    /**
     * 设置颜色背景 Parent 布局
     * @return          this
     */
    open fun backgroundColorIntByRoot(@ColorInt color: Int): DialogConfig {
        mStyle.setBackgroundColorIntByRoot( color )
        return this
    }

    /**
     * 设置资源背景 Parent 布局
     * @return          this
     */
    open fun backgroundResourceByRoot(@DrawableRes resId: Int): DialogConfig {
        mStyle.setBackgroundDrawableResourceByRoot( resId )
        return this
    }

    /**
     * 设置对话框之外的透明度
     * @param dimAmount     0.0 ~ 1.0
     * @return              this
     */
    open fun dimAmount(dimAmount: Float): DialogConfig {
        mStyle.dimAmount = dimAmount
        return this
    }

    /**
     * 设置默认的对话框之外的透明度。默认：0.6
     * @return              this
     */
    open fun defaultDimAmount(): DialogConfig {
        return dimAmount(0.6f)
    }

    /**
     * 设置对话框之外的透明度为透明。
     * @return              this
     */
    open fun transparentDimAmount(): DialogConfig {
        return dimAmount( 0F )
    }

    /**
     * 显示位置
     * @param gravity   [Gravity]
     * @return          this
     */
    open fun gravity(gravity: Int): DialogConfig {
        mStyle.gravity = gravity
        return this
    }

    open fun animations(@StyleRes resId: Int): DialogConfig {
        mStyle.animations = resId
        return this
    }

    /**
     * 中间淡入淡出动画
     * @return          this
     */
    open fun animOfCenterAlpha(): DialogConfig {
        gravity(Gravity.CENTER)
        return animations( R.style.dialogAnimOfCenterAlpha )
    }

    /**
     * 中间顶部一小段距离进出动画
     * @return          this
     */
    open fun animOfCenterTopTranslate(): DialogConfig {
        gravity( Gravity.CENTER )
        return animations( R.style.dialogAnimOfCenterTopTranslate )
    }

    /**
     * 中间底部一小段距离进出动画
     * @return          this
     */
    open fun animOfCenterBottomTranslate(): DialogConfig {
        gravity(Gravity.CENTER)
        return animations( R.style.dialogAnimOfCenterBottomTranslate )
    }

    /**
     * 顶部进出动画
     * @return          this
     */
    open fun animOfTopTranslate(): DialogConfig {
        gravity(Gravity.CENTER_HORIZONTAL or Gravity.TOP)
        return animations( R.style.dialogAnimOfTopTranslate )
    }

    /**
     * 底部进出动画
     * @return          this
     */
    open fun animOfBottomTranslate(): DialogConfig {
        gravity( Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM )
        return animations( R.style.dialogAnimOfBottomTranslate )
    }

    /**
     * 描边
     * @param width     宽度
     * @param color     颜色
     * @return          this
     */
    open fun stroke(width: Int, @ColorInt color: Int): DialogConfig {
        mStyle.setStroke(width, color)
        return this
    }

    /**
     * 对话框形状
     * @param shape     [WindowStyle.Shape]
     * @return          this
     */
    open fun shape(@WindowStyle.Shape shape: Int): DialogConfig {
        mStyle.setShape(shape)
        return this
    }

    //    private static final int REQUEST_CODE_SYSTEM_DIALOG = 3308;
    /**
     * 系统级对话框
     * @param enable    是否启用为系统级对话框
     * @return          this
     */
    @RequiresPermission(Manifest.permission.SYSTEM_ALERT_WINDOW)
    open fun systemDialog(activity: Activity, enable: Boolean): DialogConfig {
        mStyle.isSystemDialog = enable
        //6.0之后需要用户手动打开<允许显示在其他应用的上层>这个选项
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //是否已经打开过
            if (Settings.canDrawOverlays(activity)) return this
            val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
            intent.setData(Uri.parse("package:" + mContext.packageName))
            activity.startActivity(intent)
            //            activity.startActivityForResult( intent, REQUEST_CODE_SYSTEM_DIALOG );
        }
        return this
    }

    /**
     * 设置确定按钮点击事件监听器
     * @param positiveText  按钮文本内容
     * @param style         按钮样式
     * @param l             事件监听器
     * @return              this
     */
    open fun onPositiveButtonListener(
        positiveText: String?,
        style: TextStyle?,
        l: DialogInterface.OnClickListener?
    ): DialogConfig {
        dialogButton.setOnPositiveListener(positiveText, style, l)
        return this
    }

    /**
     * 设置确定按钮点击事件监听器
     * @param positiveText   文本资源
     * @param l             事件监听器
     * @return              this
     */
    open fun onPositiveButtonListener(
        positiveText: String?,
        l: DialogInterface.OnClickListener?
    ): DialogConfig {
        dialogButton.setOnPositiveListener(positiveText, l)
        return this
    }

    /**
     * 设置确定按钮点击事件监听器
     * @param positiveText   文本资源
     * @return              this
     */
    open fun onPositiveButtonListener(positiveText: String?): DialogConfig {
        dialogButton.setOnPositiveListener(positiveText)
        return this
    }

    /**
     * 设置确定按钮点击事件监听器
     * @param positiveRes   文本资源
     * @param style         按钮样式
     * @param l             事件监听器
     * @return              this
     */
    open fun onPositiveButtonListener(
        @StringRes positiveRes: Int,
        style: TextStyle?,
        l: DialogInterface.OnClickListener?
    ): DialogConfig {
        dialogButton.setOnPositiveListener(positiveRes, style, l)
        return this
    }

    /**
     * 设置确定按钮点击事件监听器
     * @param positiveRes   文本资源
     * @param l             事件监听器
     * @return              this
     */
    open fun onPositiveButtonListener(
        @StringRes positiveRes: Int,
        l: DialogInterface.OnClickListener?
    ): DialogConfig {
        dialogButton.setOnPositiveListener(positiveRes, l)
        return this
    }

    /**
     * 设置确定按钮点击事件监听器
     * @param positiveRes   文本资源
     * @return              this
     */
    open fun onPositiveButtonListener(@StringRes positiveRes: Int): DialogConfig {
        dialogButton.setOnPositiveListener(positiveRes)
        return this
    }

    /**
     * 设置确定按钮点击事件监听器
     * @param positiveRes   文本资源
     * @param style         按钮样式
     * @return              this
     */
    open fun onPositiveButtonListener(
        @StringRes positiveRes: Int,
        style: TextStyle?
    ): DialogConfig {
        dialogButton.setOnPositiveListener(positiveRes, style)
        return this
    }

    /**
     * 设置确定按钮点击事件监听器
     * @param style         按钮样式
     * @param l             事件监听器
     * @return              this
     */
    open fun onPositiveButtonListener(
        style: TextStyle?,
        l: DialogInterface.OnClickListener?
    ): DialogConfig {
        dialogButton.setOnPositiveListener(style, l)
        return this
    }

    /**
     * 设置确定按钮点击事件监听器
     * @param l             事件监听器
     * @return              this
     */
    open fun onPositiveButtonListener(l: DialogInterface.OnClickListener?): DialogConfig {
        dialogButton.setOnPositiveListener(l)
        return this
    }

    /**
     * 设置取消按钮点击事件监听器
     * @param negativeText  按钮文本内容
     * @param style         按钮样式
     * @param l             事件监听器
     * @return              this
     */
    open fun onNegativeButtonListener(
        negativeText: String?,
        style: TextStyle?,
        l: DialogInterface.OnClickListener?
    ): DialogConfig {
        dialogButton.setOnNegativeListener(negativeText, style, l)
        return this
    }

    /**
     * 设置取消按钮点击事件监听器
     * @param negativeText  按钮文本内容
     * @param l             事件监听器
     * @return              this
     */
    open fun onNegativeButtonListener(
        negativeText: String?,
        l: DialogInterface.OnClickListener?
    ): DialogConfig {
        dialogButton.setOnNegativeListener(negativeText, l)
        return this
    }

    /**
     * 设置取消按钮点击事件监听器
     * @param negativeText  按钮文本内容
     * @return              this
     */
    open fun onNegativeButtonListener(negativeText: String?): DialogConfig {
        dialogButton.setOnNegativeListener(negativeText)
        return this
    }

    /**
     * 设置取消按钮点击事件监听器
     * @param negativeRes   文本资源
     * @param style         按钮样式
     * @param l             事件监听器
     * @return              this
     */
    open fun onNegativeButtonListener(
        @StringRes negativeRes: Int,
        style: TextStyle?,
        l: DialogInterface.OnClickListener?
    ): DialogConfig {
        dialogButton.setOnNegativeListener(negativeRes, style, l)
        return this
    }

    /**
     * 设置取消按钮点击事件监听器
     * @param negativeRes   文本资源
     * @param l             事件监听器
     * @return              this
     */
    open fun onNegativeButtonListener(
        @StringRes negativeRes: Int,
        l: DialogInterface.OnClickListener?
    ): DialogConfig {
        dialogButton.setOnNegativeListener(negativeRes, l)
        return this
    }

    /**
     * 设置取消按钮点击事件监听器
     * @param negativeRes   文本资源
     * @return              this
     */
    open fun onNegativeButtonListener(@StringRes negativeRes: Int): DialogConfig {
        dialogButton.setOnNegativeListener(negativeRes)
        return this
    }

    /**
     * 设置取消按钮点击事件监听器
     * @param negativeRes   文本资源
     * @param style         按钮样式
     * @return              this
     */
    open fun onNegativeButtonListener(
        @StringRes negativeRes: Int,
        style: TextStyle?
    ): DialogConfig {
        dialogButton.setOnNegativeListener(negativeRes, style)
        return this
    }

    /**
     * 设置取消按钮点击事件监听器
     * @param style         按钮样式
     * @param l             事件监听器
     * @return              this
     */
    open fun onNegativeButtonListener(
        style: TextStyle?,
        l: DialogInterface.OnClickListener?
    ): DialogConfig {
        dialogButton.setOnNegativeListener(style, l)
        return this
    }

    /**
     * 设置取消按钮点击事件监听器
     * @param l             事件监听器
     * @return              this
     */
    open fun onNegativeButtonListener(l: DialogInterface.OnClickListener?): DialogConfig {
        dialogButton.setOnNegativeListener(l)
        return this
    }

    /**
     * Dialog Style
     */
    open fun theme(@StyleRes resId: Int): DialogConfig {
        mContext.setTheme(resId)
        return this
    }
    /**
     * 创建普通对话框
     * @param layoutRes     内容View id
     * @param params        View的布局参数
     * @return              this
     */
    @JvmOverloads
    open fun create(@LayoutRes layoutRes: Int, params: LayoutParams? = null): DialogOption {
//        val v = loadView(layoutRes)
//        if (params != null) v.layoutParams = params
//        return build(dialogLayoutParams)
        return create( loadView( layoutRes ), params )
    }

    /**
     * 创建普通对话框
     * @param layoutRes     内容View id
     * @param width         View宽度
     * @param height        View高度
     * @return              this
     */
    open fun create(@LayoutRes layoutRes: Int, width: Int, height: Int): DialogOption {
        return create(layoutRes, LayoutParams(width, height))
    }

    /**
     * 创建普通对话框
     * @param view          内容View
     * @param params        View的布局参数
     * @return              this
     */
    @JvmOverloads
    open fun create(view: View? = null, params: LayoutParams? = null): DialogOption {
        //圆角
        if ( mStyle.cornerRadius.radius < 0F ) mStyle.cornerRadius.defaultRadius()
        params?.apply { view?.layoutParams = this }
        return build( view, dialogLayoutParams )
//        return buildView( view, params, dialogLayoutParams )
    }

    /**
     * 创建普通对话框
     * @param view          内容View
     * @param width         View宽度
     * @param height        View高度
     * @return              this
     */
    open fun create(view: View, width: Int, height: Int): DialogOption {
        return create(view, LayoutParams(width, height))
    }

    /**
     * 创建自由对话框，宽高不受限制
     * @param layoutRes     内容View id
     * @param lp            View的布局参数
     * @return              this
     */
    @JvmOverloads
    open fun createOfFree(@LayoutRes layoutRes: Int, lp: LayoutParams? = null
    ): DialogOption {
        val v = loadView(layoutRes)
//        lp?.apply { v.layoutParams = lp }
        return build( v, lp )
    }

    /**
     * 创建自由对话框，宽高不受限制
     * @param layoutRes     内容View id
     * @param width         View宽度
     * @param height        View高度
     * @return              this
     */
    open fun createOfFree(@LayoutRes layoutRes: Int, width: Int, height: Int): DialogOption {
        return createOfFree(layoutRes, LayoutParams(width, height))
    }

    /**
     * 创建自由对话框，宽高不受限制
     * @param view          内容View
     * @param lp        view布局参数
     * @return              this
     */
    @JvmOverloads
    open fun createOfFree(view: View? = null, lp: LayoutParams? = null): DialogOption {
        return buildView(view, lp, null)
    }

    /**
     * 创建自由对话框，宽高不受限制
     * @param view          内容View
     * @param width         View宽度
     * @param height        View高度
     * @return              this
     */
    open fun createOfFree(view: View, width: Int, height: Int): DialogOption {
        return createOfFree(view, LayoutParams(width, height))
    }

    /**
     * 创建普通对话框，覆盖内容View的布局参数为[ViewGroup.LayoutParams.MATCH_PARENT]
     * @param layoutRes     内容View
     * @return              this
     */
    open fun createOfMatch(@LayoutRes layoutRes: Int): DialogOption {
        val v = loadView( layoutRes )
        v.layoutParams = matchLayoutParams
        return build( v, matchLayoutParams )
    }

    /**
     * 创建普通对话框，覆盖内容View的布局参数为[ViewGroup.LayoutParams.MATCH_PARENT]
     * @param view          内容View
     * @return              this
     */
    open fun createOfMatch(view: View?): DialogOption {
        return buildView( view, matchLayoutParams, matchLayoutParams )
    }

    /**
     * 创建自由对话框，创建自由对话框，宽高不受限制
     * 覆盖内容View的布局参数为[ViewGroup.LayoutParams.MATCH_PARENT]
     * @param view          内容View
     * @return              this
     */
    open fun createOfMatchAndFree(view: View?): DialogOption {
        return buildView( view, matchLayoutParams, matchLayoutParams )
    }

    /**
     * 创建自由对话框，宽高不受限制
     * 覆盖内容View的布局参数为[ViewGroup.LayoutParams.MATCH_PARENT]
     * @param layoutRes     内容View
     * @return              this
     */
    open fun createOfMatchAndFree(@LayoutRes layoutRes: Int): DialogOption {
        val lp = matchLayoutParams
        val v = loadView( layoutRes )
        v.layoutParams = lp
        return build( v, lp )
    }

    /**
     * 创建普通对话框
     * @param create    通过封装类创建
     * @return          this
     */
    open fun create(create: Create<out View>): DialogOption {
        val lp = create.layoutParams
        return if (create.isFree) {
            if (lp == null) {
                createOfFree(create.layout, create.width, create.height)
            } else {
                createOfFree(create.layout, lp)
            }
        } else {
            if (lp == null) {
                create(create.layout, create.width, create.height)
            } else {
                create(create.layout, lp)
            }
        }
    }

    /**
     * 设置标题。[android.view.Window]
     * @param title         标题内容
     * @param titleColor    标题颜色
     * @return              this
     */
    @Deprecated("Method is substituted", ReplaceWith("setTitle(title, -1)"))
    open fun titleOfWindow(title: String?, @ColorInt titleColor: Int): DialogConfig {
        val w = window ?: return title( title )
        w.setTitle( title )
        if ( titleColor != -1 ) w.setTitleColor(titleColor)
        return this
    }

    /**
     * 设置标题。[android.view.Window]
     * @param title     标题内容
     * @return          this
     */
    @Deprecated("Method is substituted", ReplaceWith("setTitleOfWindow(title, -1)"))
    open fun titleOfWindow(title: String?): DialogConfig {
        return titleOfWindow(title, -1)
    }

    /**
     * 设置标题
     * @param title     标题内容
     * @param style     文本样式
     * @return          this
     */
    open fun title(title: String?, style: TextStyle): DialogConfig {
        return if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
            var color = style.textColorInt
            if ( color == -1 ) color = resources.getColor( style.textColor )
            window?.let { titleOfWindow( title, color ) }
            return this
        } else {
            val tv = style.getTextView(mContext, title)
            val params = parentLayoutParam
            params.topMargin = dp2Px( 20 )
            tv.tag = Tag.TITLE
            tv.layoutParams = params
            addView(tv)
        }
    }

    /**
     * 设置标题
     * @param resId     标题内容
     * @param style     文本样式
     * @return          this
     */
    open fun title(@StringRes resId: Int, style: TextStyle): DialogConfig {
        return title( getString( resId ), style )
    }

    /**
     * 设置标题
     * @param title     标题内容
     * @return          this
     */
    open fun title(title: String?): DialogConfig {
        return title( title, defTitleTextStyle )
    }

    /**
     * 设置标题
     * @param resId     标题内容
     * @return          this
     */
    open fun title(@StringRes resId: Int): DialogConfig {
        return title( getString( resId ) )
    }

    /**
     * 设置显示内容
     * @param msg       消息内容
     * @param style     文本样式
     * @return          this
     */
    open fun message(msg: String?, style: TextStyle): DialogConfig {
        val tv = style.getTextView(mContext, msg)
        tv.layoutParams = parentLayoutParam
        return addView(tv)
    }

    /**
     * 设置显示内容
     * @param resId     消息内容
     * @param style     文本样式
     * @return          this
     */
    open fun message(@StringRes resId: Int, style: TextStyle): DialogConfig {
        return message( getString( resId ), style )
    }

    /**
     * 设置显示内容
     * @param msg       消息内容
     * @return          this
     */
    open fun message(msg: String?): DialogConfig {
        return message( msg, defMessageTextStyle )
    }

    /**
     * 设置显示内容
     * @param resId     消息内容
     * @return          this
     */
    open fun message(@StringRes resId: Int): DialogConfig {
        return message( getString( resId ) )
    }

    /**
     * 测量内容View。测量传入布局的实际大小。如果也传入了布局参数，则布局参数会失效。
     * 该方法主要解决设计的布局设置 [ViewGroup.LayoutParams.MATCH_PARENT] 或者
     * [ViewGroup.LayoutParams.WRAP_CONTENT] 无效时使用。
     * @return          this
     */
    open fun measure(): DialogConfig {
        enableMeasure = true
        return this
    }

    /**
     * 设置一个DialogOption，如果不设置，build之后会实例
     * 主要用于实现独立的Dialog，当class继承DialogOption之后，等同于继承了Dialog
     * @param option    为空时自动实例
     * @return          this
     */
    open fun dialogOption(option: DialogOption?): DialogConfig {
        mDialogOption = option
        return this
    }

    /**
     * 监听生命周期
     * 监听前：build时创建View
     * 监听后：等待Dialog.onCreate 触发时创建View
     */
    open fun dialogLifecycle(lifecycle: DialogLifecycle) : DialogConfig {
        dialogLifecycle = lifecycle
        return this
    }

    open fun getString(resId: Int): String { return resources.getString( resId ) }

    private fun addView(view: View, lp: LayoutParams? = null): DialogConfig {
        if (lp == null) {
            mLayout.addView(view)
        } else {
            mLayout.addView(view, lp)
        }
        return this
    }

    private fun build(view: View?, lp: LayoutParams?): DialogOption {
        view?.let { childView = it }
        mDialogButton?.apply {
            createButton()?.apply {
                tag = Tag.BUTTON
                addView( this, layoutParams )
            }
        }
        // 设置View
        if (dialogLifecycle == null) mDialog.setContentView( mLayout )
        // 默认圆角
        if ( mStyle.cornerRadius.isDefaultRadius() ) cornerRadius( dp2Px( 10 ) )
        mLayout.background = mStyle.backgroundDrawableByRoot
        //设置Window
        window?.apply {
            //显示位置 - Window
            setGravity(mStyle.gravity)
            //对话框背景
            setBackgroundDrawable( mStyle.backgroundDrawable )
            //背景透明度
            if ( mStyle.dimAmount != -1F ) {
                addFlags( WindowManager.LayoutParams.FLAG_DIM_BEHIND )
                setDimAmount( mStyle.dimAmount )
            }
            //动画
            if ( mStyle.animations != 0 ) setWindowAnimations( mStyle.animations )
            //构建系统级对话框
            buildSystemDialog(this)
        }
        val opt = mDialogOption ?: object : DialogOption() {}
        opt.buildLayoutParams = lp
        //初始DialogOption
        opt.initOption( this )
        mDialogOption = opt
        return opt
    }

    /**
     * 设置属性
     * @param lp    [ViewGroup.LayoutParams]
     */
    fun buildAttributes(lp: LayoutParams?) {
//        val wlp = window.attributes
        val viewLayoutParams = childView?.layoutParams
        val viewWidth = viewLayoutParams?.width ?: 0
        val viewHeight = viewLayoutParams?.height ?: 0
        val matchParent = LayoutParams.MATCH_PARENT
        val wrapContent = LayoutParams.WRAP_CONTENT
        // 使用提供LayoutParams，或者使用默认LayoutParams
        val layoutParams = lp ?: LayoutParams( matchParent, wrapContent )

        // 如果启用测量，则测量布局
        if ( enableMeasure ) {
            val screenWidth = resources.displayMetrics.widthPixels
            val screenHeight = resources.displayMetrics.heightPixels
            val measureView = childView ?: mLayout
            val wView = measureView.layoutParams.width
            val hView = measureView.layoutParams.height
            val wSize = if( wView == matchParent ) screenWidth else 0
            val hSize = if( hView == matchParent ) screenHeight else 0
            measureView.measure(
                View.MeasureSpec.makeMeasureSpec( wSize, getMeasureSpecMode( wView ) ),
                View.MeasureSpec.makeMeasureSpec( hSize, getMeasureSpecMode( hView ) )
            )
            layoutParams.width = measureView.measuredWidth
            layoutParams.height = measureView.measuredHeight
        } else {
            // 根据子View和LayoutParams设置宽度
            layoutParams.width = when {
                // 优先考虑 外部传入的 LayoutParams
                lp != null && lp.width > 0 -> lp.width
                // 如果子View宽度大于0，则使用子View宽度
                viewWidth > 0 -> viewWidth
                // 如果子布局的LayoutParams宽度为MATCH_PARENT，则使用 MATCH_PARENT
                viewWidth == matchParent -> matchParent
                // 否则，默认使用定义好的LayoutParams宽度
                else -> layoutParams.width
            }
            // 根据子View和LayoutParams设置高度
            layoutParams.height = when {
                // 优先考虑 外部传入的 LayoutParams
                lp != null && lp.height > 0 -> lp.height
                // 如果子View高度大于0，则使用子View高度
                viewHeight > 0 -> viewHeight
                // 如果子布局的LayoutParams高度为MATCH_PARENT，则使用 MATCH_PARENT
                viewHeight == matchParent -> matchParent
                // 否则，默认使用定义好的LayoutParams高度
                else -> layoutParams.height
            }
        }
        // 将计算后的LayoutParams应用到Window
        attributes.width = layoutParams.width
        attributes.height = layoutParams.height

        window?.attributes?.let {
            Log.w( "TAG", "============ 1 w ${attributes.width}, h ${attributes.height}")
            it.width = if( attributes.width == wrapContent ) {
                val measuredWidth = childView?.measuredWidth ?: 0
                Log.w( "TAG", "============ 2 w $measuredWidth")
                if( measuredWidth > 0 ) measuredWidth else wrapContent
            } else {
                attributes.width
            }
            it.height = if( attributes.height == wrapContent ) {
                val measuredHeight = childView?.measuredHeight ?: 0
                Log.w( "TAG", "============ 2 h $measuredHeight")
                if( measuredHeight > 0 ) measuredHeight else wrapContent
            } else {
                attributes.height
            }
        }
//        window?.setLayout( layoutParams.width, layoutParams.height )

//        ( mLayout.layoutParams ?: lp ?: LayoutParams( defaultLayoutParams ) ).let {
//            it.width = layoutParams.width
//            it.height = layoutParams.height
//            //显示位置 - Layout
//            mLayout.gravity = mStyle.gravity
//            if( it is LinearLayout.LayoutParams ) it.gravity = mStyle.gravity
//            // 获取自定义的View
//            view?.let { child ->
//                // 检查自定义View的宽高
//                ( child.layoutParams ?: LayoutParams( defaultLayoutParams ) ).let { childLp ->
//                    if( child.layoutParams.width <= 0 ) {
//                        val w = layoutParams.width.coerceAtLeast( child.minimumWidth )
//                        childLp.width = if( w <= 0 ) matchLayoutParams.width else w
//                        Log.e("TAG", "ttttttt -> w $w, ${childLp.width}, ${child.minimumWidth}, ${layoutParams.width}")
//                    }
//                    if( child.layoutParams.height <= 0 ) {
//                        val h = layoutParams.height.coerceAtLeast( child.minimumHeight )
//                        childLp.height = if( h <= 0 ) matchLayoutParams.height else h
//                        Log.e("TAG", "ttttttt -> h $h, ${childLp.height}, ${child.minimumHeight}, ${layoutParams.height}")
//                    }
//                    child.layoutParams = childLp
//                }
//            }
//            mLayout.layoutParams = it
//        }
//        for ( i in 0 until mLayout.childCount ) {
//            val v = mLayout.getChildAt( i )
//            val tag = v.tag
//            if ( Tag.TITLE == tag || Tag.BUTTON == tag ) {
//                //自定义控件情况下需要额外加上标题和按钮的高度
//                v.measure( 0, 0 )
//                if( wLP.height < 0 ) wLP.height = 0
//                wLP.height += v.measuredHeight
//            }
//        }

    }

    //测量
    private fun getMeasureSpecMode(size: Int): Int {
        return when {
            size == LayoutParams.MATCH_PARENT -> View.MeasureSpec.EXACTLY
            size > 0 -> View.MeasureSpec.AT_MOST
            else -> View.MeasureSpec.UNSPECIFIED
        }
    }

    /**
     * 设置系统级对话框
     * @param w     [Window]
     */
    private fun buildSystemDialog(w: Window) {
        if ( !mStyle.isSystemDialog ) return
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 6.0 以上需要检查悬浮窗权限
            if ( !Settings.canDrawOverlays( w.context ) ) {
                // 没有悬浮窗权限，抛出异常或进行其他处理
                throw SecurityException( "Missing permission: SYSTEM_ALERT_WINDOW. [DialogPermission.get().applyOverlayPermission(...)]" )
            }
        }
        if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ) {
            // 8.0 及以上使用 TYPE_APPLICATION_OVERLAY
            w.setType( WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY )
        } else {
            // 8.0 以下使用 TYPE_SYSTEM_ALERT
            w.setType( WindowManager.LayoutParams.TYPE_SYSTEM_ALERT )
        }
    }

    private val dialogButton: DialogButton
        /**
         * 创建/获取对话框的按钮
         * @return  对话框按钮
         */
        get() {
            val btn = mDialogButton ?: DialogButton( mContext, mDialog )
            mDialogButton = btn
            return btn
        }

    private fun loadView(@LayoutRes layoutRes: Int): View {
        return LayoutInflater.from( mContext ).inflate( layoutRes, mLayout, true )
    }

    /**
     * 创建对话框
     * @param view              内容View
     * @param viewParams        内容View的布局参数
     * @param windowParams      父布局的布局参数
     * @return                  this
     */
    private fun buildView(
        view: View?,
        viewParams: LayoutParams?,
        windowParams: LayoutParams?
    ): DialogOption {
        view?.apply {
            if( viewParams == null ) addView( this ) else addView( this, viewParams )
        }
        return build( view, windowParams )
    }

    /**
     * dp2Px
     */
    @JvmName( "dp2PxByInt" )
    internal fun dp2Px(dp: Int) : Int { return Utils.dp2Px( mContext, dp ) }
    /**
     * dp2Px
     */
    @JvmName( "dp2PxByFloat" )
    internal fun dp2Px(dp: Float) : Float { return Utils.dp2Px( mContext, dp ) }
}